Repository navigation
fix(workspace): restored panes read their persisted ghost log - #1227
Closed
Juliusolsson05 wants to merge 4 commits into
Closed
Juliusolsson05 wants to merge 4 commits into
Juliusolsson05 wants to merge 4 commits into
Conversation
Nothing had read <userData>/ghost-logs/<id>.ghost.jsonl on restore since 0cb71e9: the only reader was a spawn-time bootstrap keyed by the fresh spawn id, which never matches the persisted log after a reload. Unsent and in-flight prompts vanished from restored panes, and 1,935 of 1,952 logs on disk were orphans. The history load now reads the log under the durable session id in parallel with the transcript, reconciles it against committed turns, and appends back only entries whose state changed. The dead spawn bootstrap is removed. Fixes #1225 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05
added a commit
that referenced
this pull request
Sep 25, 2026
Review of #1227 (blocker): reading the log painted committed turns a second time at the bottom of restored feeds. Render rule 4 shows an orphan newer than the committed tail, and a logged ghost's updatedAt is its orphan time (last delta + 30 s) or, if never orphaned, the restore itself: both after its own commit. Every Codex text ghost (its response id never matches the rollout turn id) and Claude tool calls committed above the loaded window came back. Restored ghosts are now re-dated to their createdAt and marked orphaned. A crash-mid-turn ghost began after the last commit and still paints; any ghost of a turn that committed began before it and is hidden. Tests use two more real sessions (fixture stale-ghosts-after-restore) and assert on the merged feed: no stale ghost paints for Claude or Codex, and the Codex final answer paints when the tail is cut before it. Dropping the re-date fails all three. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 25, 2026
Closed
Steering note q6 on #1227: re-dating restored ghosts to createdAt hides a ghost that began before the last commit and kept streaming after it. Scanning 7,128 Codex ghosts against their rollouts found 7 such straddles (the rollout write lags the proxy; one by 34 ms), each of which a crash would have left as the only copy. The restore clock is now the ghost's last content update: the newest updatedAt among its un-orphaned records (Claude logs every update), or orphanedAt - TTL for a Codex log that holds only the orphan record (an upper bound, so in doubt it paints). What that bound lets through, a Codex response that did commit, is removed by identity: the chunk's token_usage_record names each committed response_id. GHOST_ORPHAN_TTL_MS moves to ghosts.ts, the one value the sweep and its inverse share. The recorded straddle joins the fixture; createdAt as the clock, no identity check, and no re-date each fail a different test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…passed Review of #1227 (B F1/F2, C1-C5): - A restored ghost the tail already passed is not merged. Rule 4 hides it for good and most can never be superseded (Codex ids, #1231; all 1,864 OpenCode ghosts on disk), so it was permanent cargo re-merged and swept on every restore. Only ghosts newer than the tail can paint. - Tests now pin: only supersedes are written back (#731 mutation fails), the in-memory ghost wins over the log's copy, the crash case drops the NEWEST turn and asserts what paints, and the removed deferred spawn read is caught after one macrotask. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Closing unmerged, by the owner's decision (2026-09-25). The on-disk ghost log is being removed instead of revived.
In-memory ghosts, the live streaming preview, stay. The removal PR follows. The fixtures and findings on this branch stay on it for reference. |
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1225
What was wrong
After a reload, a restored pane never read its ghost log (
<userData>/ghost-logs/<id>.ghost.jsonl), so unsent and in-flight prompts disappeared. The only reader was a spawn-time bootstrap. It looked the log up under the new spawn id, which never matches the persisted id. On disk, 1,935 of 1,952 ghost logs were orphans.Fix
initialHistory.ts:readPersistedGhosts(sessionId)runs in parallel with the history read. It merges intoloadedGhosts(the in-memory entry wins), thenreconcileUpstreamruns against the committed turns. Only changed entries are appended back throughghostsToPersist. A read failure degrades to an empty log and logs a warning.session.ts: the dead spawn-time bootstrap (68 lines) is removed.Evidence
testing/fixtures/ghost-restore/: 7 real unsuperseded ghosts from a live log, plus the 8 committed records of their turns.initialHistory.ghostRestore.renderer.test.tsx:sessionRecovery.renderer.test.tsx: the wait on the spawn bootstrap is replaced withnot.toHaveBeenCalled.tsc -bis clean.🤖 Generated with Claude Code